home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Day Cry
/
Day Cry CD.bin
/
oh_towns
/
taropyon
/
splib
/
splib.lzh
/
PRG
/
LHX
/
SLIDE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-04
|
10KB
|
482 lines
/***********************************************************
slide.c -- sliding dictionary with percolating update
***********************************************************/
#include "lh386.h"
#include <stdlib.h>
#include <string.h> /* memmove() */
#include <dos.h>
#include "slidehuf.h"
#include "intrface.h"
#ifdef __HIGHC__
# pragma On(Print_reg_vars);
# pragma On(Align_labels);
#endif
#ifdef __HIGHC__
# ifndef PASCAL
# define PASCAL (_DEFAULT_CALLING_CONVENTION | _CALLEE_POPS_STACK)
# endif
#endif
#ifdef __HIGHC__
# pragma Calling_convention(PASCAL);
#endif
static void init_slide(void);
static node child(node q, uchar c);
static void makechild(node q, uchar c, node r);
static void split(node old);
static void insert_node(void);
static void delete_node(void);
static void get_next_match(void);
#ifdef __HIGHC__
# pragma Calling_convention();
#endif
#define PERCOLATE 1
#define NIL 0
node *next = NULL;
int unpackable = 0;
ulong origsize = 0, compsize = 0;
ushort dicbit = 0;
ushort maxmatch = 0;
ulong count = 0;
ushort loc = 0;
uchar *use_ptr = NULL;
uchar text[TEXT_SIZE];
static struct encode_option encode_define[2] =
{
/* lh1 */ { output_dyn, encode_start_fix, encode_end_dyn},
/* lh4, 5 */ {(void (*)()) output_st1, encode_start_st1, encode_end_st1}
};
static struct decode_option decode_define[7] =
{
/* lh1 */ {decode_c_dyn, decode_p_st0, decode_start_fix},
/* lh2 */ {decode_c_dyn, decode_p_dyn, decode_start_dyn},
/* lh3 */ {decode_c_st0, decode_p_st0, decode_start_st0},
/* lh4 */ {decode_c_st1, decode_p_st1, decode_start_st1},
/* lh5 */ {decode_c_st1, decode_p_st1, decode_start_st1},
/* lzs */ {decode_c_lzs, decode_p_lzs, decode_start_lzs},
/* lz5 */ {decode_c_lz5, decode_p_lz5, decode_start_lz5}
};
static struct encode_option encode_set;
static struct decode_option decode_set;
static node pos = 0, matchpos = 0, avail = 0,
*position = NULL, *parent = NULL, *prev = NULL;
static int remainder = 0, matchlen = 0;
static uchar *level = NULL, *childcount = NULL;
static ushort dicsiz;
static ushort max_hash_val;
static ushort hash1, hash2;
int encode_alloc(int method)
{
if (method == 1)
{
encode_set = encode_define[0];
maxmatch = 60;
dicbit = 12;
} else
{
encode_set = encode_define[1];
maxmatch = MAXMATCH;
dicbit = 13;
}
while (1)
{
dicsiz = 1U << dicbit;
max_hash_val = 3 * dicsiz + (dicsiz / 512 + 1) * UCHAR_MAX;
level = malloc((dicsiz + UCHAR_MAX + 1) * sizeof(*level));
childcount = malloc((dicsiz + UCHAR_MAX + 1) * sizeof(*childcount));
#if PERCOLATE
position = malloc((dicsiz + UCHAR_MAX + 1) * sizeof(*position));
#else
position = malloc(dicsiz * sizeof(*position));
#endif
parent = malloc(dicsiz * 2 * sizeof(*parent));
prev = malloc(dicsiz * 2 * sizeof(*prev));
next = malloc((max_hash_val + 1) * sizeof(*next));
if (next == NULL ||
method > 1 && alloc_buf() == NULL)
{
if (next)
free(next);
if (prev)
free(prev);
if (parent)
free(parent);
if (position)
free(position);
if (childcount)
free(childcount);
if (level)
free(level);
} else
{
break;
}
if (--dicbit < 12)
error(MEMOVRERR, NULL);
}
if (method == 5)
method = dicbit - 8;
return method;
}
static void init_slide(void)
{
node i;
for (i = dicsiz; i <= dicsiz + UCHAR_MAX; i++)
{
level[i] = 1;
#if PERCOLATE
position[i] = NIL; /* sentinel */
#endif
}
for (i = dicsiz; i < dicsiz * 2; i++)
parent[i] = NIL;
avail = 1;
for (i = 1; i < dicsiz - 1; i++)
next[i] = i + 1;
next[dicsiz - 1] = NIL;
for (i = dicsiz * 2; i <= max_hash_val; i++)
next[i] = NIL;
hash1 = dicbit - 9;
hash2 = dicsiz * 2;
}
#define HASH(p, c) ((p) + ((c) << hash1) + hash2)
static node child(node q, uchar c)
/* q's child for character c (NIL if not found) */
{
node r;
r = next[HASH(q, c)];
parent[NIL] = q; /* sentinel */
while (parent[r] != q)
r = next[r];
return r;
}
static void makechild(node q, uchar c, node r)
/* Let r be q's child for character c. */
{
node h, t;
h = HASH(q, c);
t = next[h];
next[h] = r;
next[r] = t;
prev[t] = r;
prev[r] = h;
parent[r] = q;
childcount[q]++;
}
static void split(node old)
{
node new, t;
new = avail;
avail = next[new];
childcount[new] = 0;
t = prev[old];
prev[new] = t;
next[t] = new;
t = next[old];
next[new] = t;
prev[t] = new;
parent[new] = parent[old];
level[new] = matchlen;
position[new] = pos;
makechild(new, text[matchpos + matchlen], old);
makechild(new, text[pos + matchlen], pos);
}
static void insert_node(void)
{
node q, r, j, t;
uchar c, *t1, *t2;
if (matchlen >= 4)
{
matchlen--;
r = (matchpos + 1) | dicsiz;
while ((q = parent[r]) == NIL)
r = next[r];
while (level[q] >= matchlen)
{
r = q;
q = parent[q];
}
#if PERCOLATE
t = q;
while (position[t] < 0)
{
position[t] = pos;
t = parent[t];
}
if (t < dicsiz)
position[t] = pos | 0x8000;
#else
t = q;
while (t < dicsiz)
{
position[t] = pos;
t = parent[t];
}
#endif
} else
{
q = text[pos] + dicsiz;
c = text[pos + 1];
if ((r = child(q, c)) == NIL)
{
makechild(q, c, pos);
matchlen = 1;
return;
}
matchlen = 2;
}
for (;;)
{
if (r >= dicsiz)
{
j = maxmatch;
matchpos = r;
} else
{
j = level[r];
matchpos = position[r] & 0x7fff;
}
if (matchpos >= pos)
matchpos -= dicsiz;
t1 = &text[pos + matchlen];
t2 = &text[matchpos + matchlen];
while (matchlen < j)
{
if (*t1 != *t2)
{
split(r);
return;
}
matchlen++;
t1++;
t2++;
}
if (matchlen == maxmatch)
break;
position[r] = pos;
q = r;
if ((r = child(q, *t1)) == NIL)
{
makechild(q, *t1, pos);
return;
}
matchlen++;
}
t = prev[r];
prev[pos] = t;
next[t] = pos;
t = next[r];
next[pos] = t;
prev[t] = pos;
parent[pos] = q;
parent[r] = NIL;
next[r] = pos; /* special use of next[] */
}
static void delete_node(void)
{
#if PERCOLATE
node q, r, s, t, u;
#else
node r, s, t, u;
#endif
if (parent[pos] == NIL)
return;
r = prev[pos];
s = next[pos];
next[r] = s;
prev[s] = r;
r = parent[pos];
parent[pos] = NIL;
if (r >= dicsiz || --childcount[r] > 1)
return;
#if PERCOLATE
t = position[r] & 0x7fff;
#else
t = position[r];
#endif
if (t >= pos)
t -= dicsiz;
#if PERCOLATE
s = t;
q = parent[r];
while ((u = position[q]) < 0)
{
u &= 0x7fff;
if (u >= pos)
u -= dicsiz;
if (u > s)
s = u;
position[q] = (s | dicsiz);
q = parent[q];
}
if (q < dicsiz)
{
if (u >= pos)
u -= dicsiz;
if (u > s)
s = u;
position[q] = (s | dicsiz) | 0x8000;
}
#endif
s = child(r, text[t + level[r]]);
t = prev[s];
u = next[s];
next[t] = u;
prev[u] = t;
t = prev[r];
next[t] = s;
prev[s] = t;
t = next[r];
prev[t] = s;
next[s] = t;
parent[s] = parent[r];
parent[r] = NIL;
next[r] = avail;
avail = r;
}
static void get_next_match(void)
{
int n;
remainder--;
if (++pos == dicsiz * 2)
{
memmove(&text[0], &text[dicsiz], dicsiz + maxmatch);
n = fread_crc(&text[dicsiz + maxmatch], dicsiz, infile);
remainder += n;
pos = dicsiz;
}
delete_node();
insert_node();
}
void encode(struct interfacing * interface)
{
int lastmatchlen, dicsiz1;
node lastmatchpos;
infile = interface->infile;
outfile = interface->outfile;
origsize = interface->original;
dispflg = interface->dispflg;
compsize = 0;
crc = unpackable = 0;
init_slide();
encode_set.encode_start();
dicsiz1 = dicsiz - 1;
pos = dicsiz + maxmatch;
memset(&text[pos], ' ', dicsiz);
remainder = fread_crc(&text[pos], dicsiz, infile);
matchlen = 0;
insert_node();
if (matchlen > remainder)
matchlen = remainder;
while (remainder > 0 && !unpackable)
{
lastmatchlen = matchlen;
lastmatchpos = matchpos;